package vip.xiaonuo.modular.business.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.java.Log;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import vip.xiaonuo.core.dbs.CurrentDataSourceContext;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.modular.business.param.BiIndexData.QueryParam;
import vip.xiaonuo.modular.business.param.StoreQueryParam;
import vip.xiaonuo.modular.business.service.PortraitService;
import vip.xiaonuo.modular.common.DistanceHelper;
import vip.xiaonuo.modular.common.WdAnalysisConst;
import vip.xiaonuo.modular.manage.biindexdata.entity.BiIndexData;
import vip.xiaonuo.modular.manage.biindexdata.service.BiIndexDataService;
import vip.xiaonuo.modular.manage.bioperateddata.entity.BiOperatedData;
import vip.xiaonuo.modular.manage.bioperateddata.service.BiOperatedDataService;
import vip.xiaonuo.modular.manage.poidata.entity.SubTagTotal;
import vip.xiaonuo.modular.manage.poidata.mapper.BiPoiDataMapper;
import vip.xiaonuo.modular.manage.poidata.param.PoiDataParam;
import vip.xiaonuo.modular.manage.poidatatags.mapper.PoiDataTagsJoinTypeMapper;
import vip.xiaonuo.modular.manage.storeorder.entity.BiStoreOrder;
import vip.xiaonuo.modular.manage.storeorder.mapper.BiStoreOrderMapper;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 区域消费者画像统计展示
 * @Author: liu
 * @Date:2022/11/15
 */
@Service
@Log
public class PortraitServiceImpl implements PortraitService {

    @Resource
    private BiPoiDataMapper biPoiDataMapper;

    @Resource
    private BiIndexDataService biIndexDataService;

    @Resource
    private BiStoreOrderMapper biStoreOrderMapper;

    @Resource
    private PoiDataTagsJoinTypeMapper poiDataTagsJoinTypeMapper;

    @Resource
    private BiOperatedDataService biOperatedDataService;
    /**
     * 查询单个点位的网格画像
     * @param param
     * @return
     */
    @Override
    public JSONObject queryGridPortrait(QueryParam param) {
        BigDecimal[] polygonArrayRange = null;
        //获取网格的经纬度
        if (StringUtils.isNotEmpty(param.getGrid())) {
            LambdaQueryWrapper<BiIndexData> w = new LambdaQueryWrapper<>();
            w.eq(BiIndexData::getGrid, param.getGrid());
            w.last(" limit 1 ");
            CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
            BiIndexData one = biIndexDataService.getOne(w);
            CurrentDataSourceContext.clearDataSourceType();
            JSONArray polygon = biIndexDataService.changeMultipolygon(one.getMultipolygon());
            polygonArrayRange = DistanceHelper.getPolygonArrayRange(polygon);
            if (polygonArrayRange != null) {
                BigDecimal lng1 = polygonArrayRange[0];
                BigDecimal lng2 = polygonArrayRange[1];
                BigDecimal lat1 = polygonArrayRange[2];
                BigDecimal lat2 = polygonArrayRange[3];
                param.setLng1(lng1.toPlainString());
                param.setLng2(lng2.toPlainString());
                param.setLat1(lat1.toPlainString());
                param.setLat2(lat2.toPlainString());
            }
        }
        JSONObject jsonObject = this.statisticsGridPortrait(param);
        jsonObject.put("imageWord", calculateImageWord(polygonArrayRange));
        return jsonObject;
    }

    /**
     * 计算某个区域的画像信息
     * 返回HashMap(标签类型类型值：比例)
     * @param polygon
     */
    public HashMap<String,Double> calculateImageWord(BigDecimal[] polygon){
        if (polygon == null || polygon.length == 0) {
            return new HashMap();
        }
        PoiDataParam poiDataParam = new PoiDataParam();
        // 查询某个区域的中类标签及比例 （比例=数量/总数）
        poiDataParam.setLng1(polygon[0].doubleValue());
        poiDataParam.setLng2(polygon[1].doubleValue());
        poiDataParam.setLat1(polygon[2].doubleValue());
        poiDataParam.setLat2(polygon[3].doubleValue());
        CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
        List<SubTagTotal> dataList = biPoiDataMapper.groupBySubTag(poiDataParam);
        CurrentDataSourceContext.clearDataSourceType();
        if(CollectionUtil.isEmpty(dataList)){
            return new HashMap();
        }

        long sum = dataList.stream().mapToLong(t -> t.getTotal()).sum();
        HashMap<String, Double> doubleHashMap = new HashMap<>();
        dataList.forEach(el->{
            doubleHashMap.put(el.getSubTag(), (el.getTotal()+0D)/sum);
        });

        // 循环中类标签 找到这个中类标签 配置的 多个标签类型 放到Map中(相同标签类型累加)
        HashMap<String, Double> calcMap = new HashMap<>();
        doubleHashMap.forEach((tagsName,val)->{
            List<String> typeValueList = poiDataTagsJoinTypeMapper.selectTypeValueByTagsName(tagsName);
            if(CollectionUtil.isNotEmpty(typeValueList)){
                typeValueList.forEach(typeValue ->{
                    Double aDouble = calcMap.get(typeValue);
                    if (aDouble != null) {
                        aDouble += val;
                    }else{
                        aDouble = val;
                    }
                    calcMap.put(typeValue, aDouble);
                });
            }
        });
        HashMap<String, Double> result = new HashMap<>();
        calcMap.forEach((k,v)->{
            if(v>0.2){
                result.put(k, new BigDecimal(v).setScale(4,4).doubleValue());
            }
        });

        return result;
    }


    @Override
    public JSONObject statisticsGridPortrait(QueryParam param) {
        String cityName = param.getCityName();
        //文化程度
        String[] culture = {"幼儿园","小学","中学","高等院校","职业技术学校","成人教育"};
        //地域
        String[] domain = {"公园","宗教","广场","动物园","村庄","公交车站"};
        //消费偏好
        String[] consumePreference = {"家电数码", "超市", "市场", "便利店", "家居建材",
                "花鸟鱼虫", "商业街", "文体用品", "百货商场", "免税店", "购物中心"};

        Map<String, String[]> tagDetailedMap = new HashMap<>();
        tagDetailedMap.put("culture",culture);
        tagDetailedMap.put("domain",domain);
        tagDetailedMap.put("consumePreference",consumePreference);
        // =============^^^^^^^以上是自定义配置^^^^^^^^^=========================
        if (StringUtils.isEmpty(cityName)) {
            cityName = "武汉市";
        }
        //查询clickhouse数据库的bi_poi_data表
        List<String> subTagList = tagDetailedMap.values().stream()
                .flatMap(e->Arrays.stream(e)).collect(Collectors.toList());
        PoiDataParam p = new PoiDataParam();
        p.setSubTagNames(subTagList);
        if (StringUtils.isNotEmpty(param.getLng1())) {
            p.setLng1(Double.parseDouble(param.getLng1()));
            p.setLng2(Double.parseDouble(param.getLng2()));
            p.setLat1(Double.parseDouble(param.getLat1()));
            p.setLat2(Double.parseDouble(param.getLat2()));
        }
        p.setCityName(cityName);

        CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
        List<SubTagTotal> subTagTotals = biPoiDataMapper.groupBySubTag(p);
        CurrentDataSourceContext.clearDataSourceType();

        //查询所有的子标签的poi数据，然后分类
        Map<String, List<SubTagTotal>> classifyMap = new HashMap<>();
        for (Map.Entry<String,String[]> entry : tagDetailedMap.entrySet()) {
            String key = entry.getKey();
            List<String> strings = Arrays.asList(entry.getValue());
            List<SubTagTotal> subList = new ArrayList<>();
            for (SubTagTotal b : subTagTotals) {
                if (strings.contains(b.getSubTag())) {
                    subList.add(b);
                }
            }
            classifyMap.put(key, subList);
        }
        //处理每一类的poi的数量，并组装返回报文
        JSONObject result = new JSONObject();
        for(Map.Entry<String,List<SubTagTotal>> entry : classifyMap.entrySet()){
            String key = entry.getKey();
            HashMap<String, Long> countMap = new HashMap<>();
            for (SubTagTotal b : entry.getValue()) {
                countMap.put(b.getSubTag(), b.getTotal());
            }
            JSONArray list = new JSONArray();
            for(String name : tagDetailedMap.get(key)){
                Long count = countMap.get(name);
                if (count == null) {
                    count = 0L;
                }
                JSONObject element = new JSONObject();
                element.put("name", name);
                element.put("value", count);
                list.add(element);
            }
            result.put(key, list);
        }
        return result;
    }

    /**
     * 门店消费堵画像统计分析
     * 店铺消费的金额、消费的时间偏好画像
     * 消费金额：（ 0.01~12.00，12.01~25.00，25.01~37.00，37.01~50.00，50.01以上）
     * 时间偏好： 工作日和周末占比（饼状图）
     * @param param
     * @return
     */
    @Override
    public JSONObject queryStorePortrait(StoreQueryParam param) {
        if (StringUtils.isEmpty(param.getStoreCode())) {
            throw new ServiceException(9, "门店编号【storeCode】不能为空");
        }
        CurrentDataSourceContext.setDataSourceType(WdAnalysisConst.CLICKHOUSE_DATASOURCE);
        JSONObject result = new JSONObject();
        //消费金额
        JSONArray amountLevelList = new JSONArray();
        {
            LambdaQueryWrapper<BiStoreOrder> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BiStoreOrder::getStoreCode, param.getStoreCode());
            wrapper.between(BiStoreOrder::getTradeAmount, 0.01, 12);
            JSONObject element = new JSONObject();
            element.put("name","0.01~12.00");
            element.put("value",biStoreOrderMapper.selectCount(wrapper));
            amountLevelList.add(element);
        }
        {
            LambdaQueryWrapper<BiStoreOrder> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BiStoreOrder::getStoreCode, param.getStoreCode());
            wrapper.between(BiStoreOrder::getTradeAmount, 12.01, 25);
            JSONObject element = new JSONObject();
            element.put("name","12.01~25.00");
            element.put("value",biStoreOrderMapper.selectCount(wrapper));
            amountLevelList.add(element);
        }
        {
            LambdaQueryWrapper<BiStoreOrder> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BiStoreOrder::getStoreCode, param.getStoreCode());
            wrapper.between(BiStoreOrder::getTradeAmount, 25.01, 37);
            JSONObject element = new JSONObject();
            element.put("name","25.01~37.00");
            element.put("value",biStoreOrderMapper.selectCount(wrapper));
            amountLevelList.add(element);
        }
        {
            LambdaQueryWrapper<BiStoreOrder> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BiStoreOrder::getStoreCode, param.getStoreCode());
            wrapper.between(BiStoreOrder::getTradeAmount, 37.01, 50);
            JSONObject element = new JSONObject();
            element.put("name","37.01~50.00");
            element.put("value",biStoreOrderMapper.selectCount(wrapper));
            amountLevelList.add(element);
        }
        {
            LambdaQueryWrapper<BiStoreOrder> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(BiStoreOrder::getStoreCode, param.getStoreCode());
            wrapper.gt(BiStoreOrder::getTradeAmount, 50);
            JSONObject element = new JSONObject();
            element.put("name","50.01以上");
            element.put("value",biStoreOrderMapper.selectCount(wrapper));
            amountLevelList.add(element);
        }
        result.put("amountLevelList", amountLevelList);

        //时间偏好
        JSONArray timeLevelList = new JSONArray();
        Integer weekendCount = 0; //周末
        Integer workdayCount = 0; //工作日
        List<Map<String, Object>> maps = biStoreOrderMapper.countOrderByWeek(param.getStoreCode());
        for (Map<String, Object> m : maps) {
            int week = Integer.parseInt(String.valueOf(m.get("week")));
            int count = Integer.parseInt(String.valueOf(m.get("total")));
            if(week <=5 ){
                workdayCount += count;
            }else{
                weekendCount += count;
            }
        }
        {
            JSONObject element = new JSONObject();
            element.put("name","工作日");
            element.put("value",workdayCount);
            timeLevelList.add(element);
        }
        {
            JSONObject element = new JSONObject();
            element.put("name","周末");
            element.put("value",weekendCount);
            timeLevelList.add(element);
        }
        result.put("timeLevelList", timeLevelList);
        CurrentDataSourceContext.clearDataSourceType();
        return result;
    }
}
